#Requires AutoHotkey v2.0
#Include FileTool.ahk
#Include SimLog.ahk
#Include FilePool.ahk
#Include FD_TrayMenu.ahk
#Include FD_HotStringsGUI.ahk

; 热字符串管理器类定义
class Corin {

    ; 名称
    name := "[FD_HotStrings V1.15_bate]"

    ; 日志对象
    log := SimLog()

    ; 文件操作工具
    fileTool := FileTool()

    ; 文件池（用于管理配置文件）
    hsConf := FilePool()

    ; 系统热字符串对象集合
    hs := Map()

    ; 系统热字符串注释集合
    hsNote := Map()

    ; 用户自定义热字符串对象集合
    userHs := Map()

    ; 类与类之间的数据传输结构体
    dataTemp := Object()

    ; 用户配置热字符串保存路径
    userHsIni := Format("{1}\FD_HotStrings\FD_HotStrings.ini", this.log.PATH_FD)

    ; 构造函数
    __New() {
        this.log.logPath := Format("{1}\FD_HotStrings.Log", this.log.PATH_FD)
        this.log.log("",false)
        this.log.info(Format("{1} 启动", this.name))
        this._def() ; 初始化流程
    }

    _def() {

        ; 设置热字符串的触发结束字符
        Hotstring("EndChars", " `n,")  ; 换行、空格、逗号

        ; 添加系统预设热字符串
        this.addHs()

        ; 添加用户定义热字符串
        this.addUserHs()

        ; 将数据传递给 GUI/托盘菜单等
        this.passDataTemp()
    }

    ; 添加系统默认热字符串定义
    addHs() {

        ; 每组包含注释说明与功能函数
        
        this.hsNote["rq"] := {note: "当前日期(yyyyMMdd格式)", enable: true}
        this.hs["rq"] := (h) => NiCole.rq(h)
        
        this.hsNote["rq-"] := {note: "当前日期(yyyy-MM-dd格式)", enable: true}
        this.hs["rq-"] := (h) => NiCole.rq1(h)
        
        this.hsNote["rq."] := {note: "当前日期(yyyy.MM.dd格式)", enable: true}
        this.hs["rq."] := (h) => NiCole.rq2(h)
        
        this.hsNote["rq/"] := {note: "当前日期(yyyy/MM/dd格式)", enable: true}
        this.hs["rq/"] := (h) => NiCole.rq3(h)
        
        this.hsNote["sj"] := {note: "当前时间(yyyy-MM-dd HH:mm:ss格式)", enable: true}
        this.hs["sj"] := (h) => NiCole.time(h)

        this.hsNote["sj8"] := {note: "随机字符(8位)", enable: true}
        this.hs["sj8"] := (h) => NiCole.sj8(h)
        
        this.hsNote["sj16"] := {note: "随机字符(16位)", enable: true}
        this.hs["sj16"] := (h) => NiCole.sj16(h)

        this.hsNote["ad"] := {note: "中国移动管理员账号(CMCCAdmin)", enable: true}
        this.hs["ad"] := (h) => NiCole.out("CMCCAdmin")

        this.hsNote["ps"] := {note: "中国移动默认管理密码(aDm8H%MdA)", enable: true}
        this.hs["ps"] := (h) => NiCole.out("aDm8H%MdA")

        ; 注册系统热字符串
        for key, value in this.hs {
            Hotstring("::" . key, value, true)
        }
        
        ; 记录日志
        this.log.info(Format("{1} 系统热字符串配置完成", this.name))
    }

    ; 添加用户自定义热字符串
    addUserHs() {
        this.hsConfInit() ; 配置文件优先级初始化
        hsConfList := this.hsConf.GetSorted()

        ; 遍历文件池，读取所有键值对
        loop hsConfList.Length {
            NiCole.splitKV(this.FileTool.read(hsConfList[A_Index].path), this.userHs)

            ; 删除临时热串文件，仅保留默认文件
            if (this.userHsIni != hsConfList[A_Index].path){
                FileDelete(hsConfList[A_Index].path)
            }
        }

        ; 把热串写入配置文件
        NiCole.writeMap(this.userHsIni, this.userHs)

        ; 注册用户热字符串
        NiCole.setUserHs(this.userHs)
        
        ; 记录日志
        this.log.info(Format("{1} 用户热字符串配置完成", this.name))
    }

    ; 初始化配置文件池优先级
    hsConfInit() {
        this.hsConf.Add(this.userHsIni, 1)
        this.hsConf.Add("FD_HotStrings.ini", 2)
        this.hsConf.Add("快捷字符串.txt", 3)
    }

    ; 数据传输给 GUI、菜单等模块
    passDataTemp() {
        this.dataTemp.userHs := this.userHs
        this.dataTemp.hs := this.hs
        this.dataTemp.hsNote := this.hsNote
        this.dataTemp.log := this.log
        this.dataTemp.userHsIni := this.userHsIni
        this.trayMenu := FD_TrayMenu(this.dataTemp)
    }

    ; 程序退出时会执行的回调函数
    onExit(ExitReason, ExitCode){

        ; 记录日志
        this.log.info(Format("{1} 退出程序", this.name))
    }

}

; 工具类定义（包含热串实现、文件处理、输出方式等）
class NiCole {

    ; 名称
    static name := "[NiCole]"

    ; 日志对象
    static log := SimLog()
    
    ; 输出模式：默认剪贴板
    static outModel := "clip" 
    
    ; 文件工具对象
    static fileTool := FileTool()

    ; 根据输出模式输出内容
    static out(text) {
        switch this.outModel {
            case "send":
                SendInput(text)
            case "clip":
                this._clip(text)
            default:
                this.outModel := "send"
                this.out(text)
        }
    }

    ; 以剪贴板方式输出
    static _clip(text) {
        this._before_Clip()

        A_Clipboard := ""
        Sleep(11)
        A_Clipboard := text
        ClipWait(2)
        if A_Clipboard == text {
            Send("^v")
        } else {
            MsgBox "剪贴板内容未能成功更新。"
        }
    }

    ; 输出前钩子（留作扩展）
    static _before_Clip() {
        ; 可自定义扩展逻辑
    }

    ; 将文本按行分割为键值对并写入 Map
    static splitKV(text, Map := 0) {
        continueFlag := false
        line := ""
        lines := []
        sChars := ['`r', '`n']

        loop parse text {
            ch := A_LoopField
            loop sChars.Length {
                if (ch == sChars[A_Index]) {
                    if (line != "") {
                        lines.push(line)
                    }
                    line := ""
                    continueFlag := true
                    continue
                }
            }
            if (continueFlag) {
                continueFlag := false
                continue
            }
            line .= ch
        }

        lines.push(line)

        splitKV_ch := "="
        KVs := map || Map()
        if (Type(KVs) != "Map") {
            KVs := Map()
        }

        loop lines.length {
            if InStr(lines[A_Index], "=") {
                kv := StrSplit(lines[A_Index], "=", , 2)
                key := Trim(kv[1])
                value := Trim(kv[2])
                KVs.Set(key, value)
            }
        }

        return KVs
    }

    ; 将 Map 写入文件
    static writeMap(path, kvMap) {
        temp := ""
        for key, value in kvMap {
            temp .= Format("{1}={2}`n", key, value)
        }
        this.fileTool.write(path, temp, "w")
        return temp
    }

    ; 配置(注册)用户热字符串
    static setUserHs(userHs){
        
        for key, value in userHs {
            Hotstring("::" . key, (key) => NiCole.out(userHs.Get(SubStr(A_ThisHotkey, 3))), true)
        }
    }

    ; 随机字符生成
    static randCh(length, range := "C", isStr := 0) {
        local chars := ""

        if (!(range is String)) {
            return ""
        }

        if (!isStr) {
            range := StrReplace(range, "C", "NUL")
            range := StrReplace(range, "A", "UL")

            local num := "1234567890"
            local upper := "abcdefghijklmnopqrstuvwxyz"
            local lower := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

            loop Parse range {
                switch (A_LoopField) {
                    case "N":
                        chars .= num
                        num := ""
                    case "U":
                        chars .= upper
                        upper := ""
                    case "L":
                        chars .= lower
                        lower := ""
                    default:
                        continue
                }
            }
        } else {
            chars := range
        }

        if (length <= 0) {
            return ""
        }

        Loop length {
            randomIndex := Random(1, StrLen(chars))
            randomChar := SubStr(chars, randomIndex, 1)
            randomString .= randomChar
        }

        return randomString
    }

    ; 当前日期 yyyyMMdd
    static rq(h) {
        today := FormatTime("", "yyyyMMdd")
        this.out(today)
    }

    ; 当前日期 yyyy-MM-dd
    static rq1(h) {
        today := FormatTime("", "yyyy-MM-dd")
        this.out(today)
    }

    ; 当前日期 yyyy.MM.dd
    static rq2(h) {
        today := FormatTime("", "yyyy.MM.dd")
        this.out(today)
    }

    ; 当前日期 yyyy/MM/dd
    static rq3(h) {
        today := FormatTime("", "yyyy/MM/dd")
        this.out(today)
    }

    ; 当前时间 yyyy-MM-dd HH:mm:ss
    static time(h) {
        now := FormatTime("", "yyyy-MM-dd HH:mm:ss")
        this.out(now)
    }

    ; 随机字符串 8 位
    static sj8(h) {
        this.out(Nicole.randCh(8))
    }

    ; 随机字符串 16 位
    static sj16(h) {
        this.out(Nicole.randCh(16))
    }
}
